
package cell

import (
	"github.com/treelab/updatecolumn/models"
)

// InstanceType of cell
func InstanceType() int32 {
	return models.RecordReference
}

  //#region Cell value convert
  cellValueToString({ cell }: IColumnAndCell) {
    const foreignRow = cell.hasForeignRow.get();
    return foreignRow.map(row => row.visibleName || UNNAMED).join(', ');
  }

  cellValueToNumber({ cell }: IColumnAndCell) {
    const foreignRows = cell.hasForeignRow.get();
    let result = 0;
    if (foreignRows.length) {
      result = parseFloat(
        _.join(
          foreignRows.map(row => row.visibleName || UNNAMED),
          '',
        ).replace(/[^0-9.-]/g, ''),
      );
    }
    return isNaN(result) ? 0 : result;
  }

  cellValueToRating({ cell }: IColumnAndCell) {
    const foreignRows = cell.hasForeignRow.get();
    let finalRating = 0;
    if (foreignRows.length) {
      const rating = foreignRows.map((row: any) => row.visibleName || UNNAMED);
      if (!_.isNaN(Number(rating[0]))) {
        finalRating = Math.round(Number(rating[0]));
      }
    }
    return finalRating;
  }

  cellValueToDatetime({ cell }: IColumnAndCell) {
    const foreignRow = cell.hasForeignRow.get();
    if (foreignRow && foreignRow.length) {
      const referenceText = foreignRow.map(row => row.visibleName || UNNAMED);
      return referenceText[0].trim();
    }
    return '';
  }

  cellValueToCheckbox({ cell }: IColumnAndCell) {
    const foreignRow = cell.hasForeignRow.get();
    if (foreignRow && foreignRow.length) {
      const number = foreignRow.map(row => row.visibleName || UNNAMED);
      if (number.length) {
        return number[0] === 'true' || number[0] === 'checked';
      }
    }
    return false;
  }

  cellValueToSelect({ column, cell }: IColumnAndCell) {
    const foreignRows = cell.hasForeignRow.get();
    if (foreignRows.length) {
      const cellsWithVisibleName = foreignRows.map((row: any) => row.visibleName || UNNAMED);
      const option = _.find(column.hasColumnOption.get(), i => _.trim(i.name) === _.trim(cellsWithVisibleName[0]));
      return option;
    }
  }

  cellValueToMultiSelect({ cell, column }: IColumnAndCell) {
    const foreignRows = cell.hasForeignRow.get();
    if (foreignRows.length) {
      const cellsWithVisibleName = foreignRows.map((row: any) => row.visibleName || UNNAMED);
      const options = _.filter(column.hasColumnOption.get(), i => _.trim(i.name) === _.trim(cellsWithVisibleName[0]));
      return options;
    }
    return [];
  }
  //#endregion

  // @TODO 循环关联表的 visablename 直接做关联
  async convertCell(command: UpdateColumn_v2, o: CommonOptions, { columnCopy }: { columnCopy: Column }) {
    const { column } = command;
    const { columnType: fromType } = columnCopy;

    const cells = column.hasCell.get();
    const events = new EventHelper();
    const fromCellHandle = this.instanceFactory.getCellInstance(fromType as ColumnType);
    if (this.needEmptyCell({ ...command, column: columnCopy })) {
      fromCellHandle.emptyCells(command, cells, false, o);
      if (cells.length) {
        _.forEach(cells, cell => {
          // remove all cell when other columntype to reference column
          const action = {
            type: UpdateAction.SET_VALUE,
            value: {
              type: command.columnConfig.type,
              foreignRowIds: [],
            },
          };
          const updateCell: UpdateCell_v2 = {
            ...command,
            action,
            _metadata: { ...command._metadata, source: Source.SAGA },
          };
          this.upsertCell(cell, { command: updateCell }, { ...o, events }, { columnCopy });
          /*
           * The columnId of the cell in the symmetric column cant be added because the new column cant get it
           */
          // const visableName = fromCellHandle.cellValueToString({
          //   column: columnCopy,
          //   cell: SourceCells.find(c => c.uid === cell.uid)!,
          // });
          // if (_.trim(visableName)) {
          //   const foreignRow = symmetricRow.find(r => r.visibleName === visableName);
          //   if (foreignRow) {
          //     // add column foreign row
          //     this.addCellForeignRow(command, cell.rowId!, foreignRow.uid!, {...o, events});
          //     // add symmectri colymn foreign row
          //     const symmectriCommnad = {
          //       workspaceId: column.foreignWorkspaceId,
          //       coreId: column.foreignCoreId,
          //       tableId: column.foreignTableId,
          //       column: symmetricColumn,
          //       _metadata: command._metadata,
          //     };
          //     this.addCellForeignRow(symmectriCommnad, foreignRow.uid!, cell.rowId, {...o, events});
          //   }
          // }
        });
      }
    }

    o.events.bulkAddEvents(...events);
    return this;
  }

  setCellValue({ cell, action }: ICCAction, o: CommonOptions) {
    const { delQuads } = o!;
    const { value, type: actionType } = action;
    // const { source } = options;
    const { foreignRowIds } = value as RecordReferenceCellValue;
    const foreignRow = cell.hasForeignRow.get();
    const arrayOrder = foreignRow.length || 0;

    if (actionType === UpdateAction.ADD_VALUE || actionType === UpdateAction.SET_VALUE) {
      const numForeignRows: number = arrayOrder ? arrayOrder : 0;
      // if (actionType === UpdateAction.SET_VALUE && source === Source.USER && cell.uid && !isNewCell) {
      //   const delEdgeIds: string[] = (cell as any).foreignRows.map(({ id }: { id: string }) => id);
      //   delEdgeIds.forEach(edgeId =>
      //     delQuads.push(...this.dgraphHelperService.getRemoveEdgeQuads(cell.uid!, Relation.HAS_FOREIGN_ROW, edgeId)),
      //   );
      //   numForeignRows = 0;
      // }
      _.forEach(foreignRowIds, (_rowId, order: number) =>
        this.createReferenctForeignRow(
          {
            cell,
            rowId: _rowId,
            order: numForeignRows + order,
          },
          o,
        ),
      );
    }
    if (actionType === UpdateAction.REMOVE_VALUE) {
      if (!cell.uid) {
        throw new Error('cannot remove value from cell');
      }

      _.forEach(foreignRowIds, foreignRowId => {
        /**
         * cannot use cell.hasForeignRow.delete(foreignRow) here because it will completely delete foreignRow
         * manually mutate cell.hasForeignRow so that its dependent cell will be updated correctly
         */
        _.remove((cell.hasForeignRow as any)._data, ({ uid }: any) => uid === foreignRowId);
        delQuads.push(
          ...this.dgraphHelperService.getRemoveEdgeQuads(cell.uid!, Relation.HAS_FOREIGN_ROW, foreignRowId),
        );
      });
    }
    return this;
  }

  getCellValue(cell: CellData) {
    return cell.foreignRow || [];
  }

  protected addCellUpdateEvent(command: UpdateCell_v2, cell: Cell, o: CommonOptions) {
    super.addCellUpdateEvent(command, cell, o, ['cellId', 'symmetricColumnId']);
  }

  protected addCellForeignRow(
    {
      workspaceId,
      coreId,
      tableId,
      column,
      _metadata,
    }: {
      workspaceId: string;
      coreId: string;
      tableId: string;
      column: Column;
      _metadata: CommandMetadata;
    },
    rowId: string,
    foreignRowId: string,
    o: CommonOptions,
  ) {
    if (foreignRowId) {
      const cell = column.hasCell.get().find(c => c.rowId === rowId);

      const action = {
        type: UpdateAction.SET_VALUE,
        value: {
          type: ColumnType.RECORD_REFERENCE,
          foreignRowIds: [foreignRowId],
        },
      };
      const updateCell = {
        workspaceId,
        coreId,
        tableId,
        column,
        rowId,
        action,
        _metadata: { ..._metadata, source: Source.SAGA },
      };
      super.upsertCell(cell, { command: updateCell }, o);
    }
  }

  needEmptyCell(command: UpdateColumn_v2) {
    const { column } = command;
    const recordReferenceColumnConfig = command.columnConfig as RecordReferenceColumnConfig;
    return !(
      column.columnType === this.instanceType &&
      column.foreignCoreId === recordReferenceColumnConfig.foreignCoreId &&
      column.foreignTableId === recordReferenceColumnConfig.foreignTableId &&
      column.foreignWorkspaceId === recordReferenceColumnConfig.foreignWorkspaceId &&
      column.symmetricColumnId === recordReferenceColumnConfig.symmetricColumnId
    );
  }

  emptyCells(command: UpdateColumn_v2, cells: readonly Cell[], deleteCells: boolean, o: CommonOptions) {
    if (!deleteCells) {
      _.forEach(cells, (cell: Cell) => {
        cell.hasForeignRow.deleteAll();
        o.delQuads.push(...this.dgraphHelperService.getRemoveEdgeQuads(cell.uid!, Relation.HAS_FOREIGN_ROW));
      });
    }
    super.emptyCells(command, cells, deleteCells, o);
    return this;
  }

  protected createReferenctForeignRow(
    { cell, rowId, order }: { cell: Cell; rowId: string; order: number },
    o: CommonOptions,
  ): Row {
    const foreignRowCell = find(cell.hasDependentCell.get(), dependCell => dependCell.rowId === rowId);
    const visibleName = get(foreignRowCell, 'row.visibleName', 'Unnamed');

    const row = new Row();
    row.uid = rowId;
    row.visibleName = visibleName;

    cell.hasForeignRow.withFacet(new OrderFacet({ order })).add(row);
    return row;
  }

